#include <atomic>
#include <chrono>
#include <cstring>
#include <fstream>
#include <future>
#include <thread>
#include <vector>
#include <filesystem>
#include "gtest/gtest.h"
#define private public
#include "async_logger.h"
#include "async_fsync.h"
#include "file_output_strategy.h"
#include "console_output_strategy.h"
#undef private

#define UNUSED(x) (void)(x)
namespace Base {
namespace SystemLog {
using namespace std::chrono_literals;

namespace {
constexpr const char* TEST_LOG_DIR = "out/tests/logs";
const char TEST_CHAR = 't';
constexpr int TEST_THREADS = 8;
constexpr int TEST_MESSAGES_COUNT = 1000;
constexpr size_t TEST_MESSAGE_SIZE = 64;
constexpr size_t TEST_MB = 1024 * 1024;
constexpr size_t TEST_BUFFER_SIZE = 1 * TEST_MB;
constexpr uint32_t TEST_FLUSH_INTERVAL_MS = 50;
constexpr size_t TEST_SOFT_FLUSH_THRESHOLD = TEST_BUFFER_SIZE / 4;
constexpr size_t TEST_HARD_FLUSH_THRESHOLD = TEST_BUFFER_SIZE / 2;

class PerfTimer {
public:
    PerfTimer() : start_(std::chrono::high_resolution_clock::now()) {}

    double elapsed() const {
        auto end = std::chrono::high_resolution_clock::now();
        return std::chrono::duration<double>(end - start_).count();
    }

private:
    std::chrono::time_point<std::chrono::high_resolution_clock> start_;
};

class TestOutput {
public:
    ErrCode operator()(const char* data, size_t len) {
        std::lock_guard<std::mutex> lock(mutex_);
        output_.append(data, len);
        totalBytes_ += len;
        return ERR_OK;
    }

    const std::string &GetOutput() {
        std::lock_guard<std::mutex> lock(mutex_);
        return output_;
    }

    size_t GetTotalBytes() {
        std::lock_guard<std::mutex> lock(mutex_);
        return totalBytes_;
    }

    void Clear() {
        std::lock_guard<std::mutex> lock(mutex_);
        output_.clear();
        totalBytes_ = 0;
    }

private:
    std::string output_;
    size_t totalBytes_ = 0;
    std::mutex mutex_;
};

} // namespace

class AsyncFsyncPerformanceTest : public testing::Test {
protected:
    static void SetUpTestCase(void);
    static void TearDownTestCase(void);
    void SetUp();
    void TearDown();

    std::unique_ptr<AsyncLogger<TEST_BUFFER_SIZE>> logger_;
    std::shared_ptr<TestOutput> testOutput_;
    std::string testDir_;
};

void AsyncFsyncPerformanceTest::SetUpTestCase(void)
{}

void AsyncFsyncPerformanceTest::TearDownTestCase(void)
{}

void AsyncFsyncPerformanceTest::SetUp()
{
    // 创建测试目录
    testDir_ = std::string(TEST_LOG_DIR) + "/test_async_fsync_performance_logs";
    std::filesystem::create_directories(testDir_);

    // 创建日志器和测试输出
    logger_ = std::make_unique<AsyncLogger<TEST_BUFFER_SIZE>>();
    testOutput_ = std::make_shared<TestOutput>();
    
    // 创建一个自定义输出策略来替代SetOutputFunction
    class TestOutputStrategy : public IOutputStrategy {
        std::shared_ptr<TestOutput> testOutput_;
    public:
        TestOutputStrategy(std::shared_ptr<TestOutput> output) : testOutput_(std::move(output)) {}
        ErrCode Write(const char* data, size_t len) override {
            return (*testOutput_)(data, len);
        }
        ErrCode Flush() override { return ERR_OK; }
        ErrCode Close() override { return ERR_OK; }
        std::string GetName() const override { return "TestOutputStrategy"; }
    };
    
    logger_->AddOutputStrategy(std::make_unique<TestOutputStrategy>(testOutput_));
    logger_->SetFlushThreshold(TEST_SOFT_FLUSH_THRESHOLD, TEST_HARD_FLUSH_THRESHOLD);
    logger_->SetFlushInterval(TEST_FLUSH_INTERVAL_MS);
}

void AsyncFsyncPerformanceTest::TearDown()
{
    if (logger_) {
        logger_->Stop();
        logger_.reset();
    }
    
    // 清理测试目录
    try {
        if (std::filesystem::exists(testDir_)) {
            std::filesystem::remove_all(TEST_LOG_DIR);
        }
    } catch (const std::filesystem::filesystem_error &ex) {
        GTEST_LOG_(ERROR) << "Failed to remove test directory: " << ex.what() << std::endl;
    }
}

/**
 * @tc.name: AsyncFsyncPerformanceTest_001
 * @tc.desc: verify high concurrency performance with AsyncFsync
 * @tc.type: PERF
 */
TEST_F(AsyncFsyncPerformanceTest, AsyncFsyncPerformanceTest_001)
{
    auto& logger = AsyncLogger<>::GetInstance();

    FileOutputOptions options;
    options.filePathPattern = testDir_ + "/perf_test.log";
    options.useAsyncFsync = true;
    options.asyncFsyncIntervalMs = 1000;
    options.maxFileSize = 10 * TEST_MB;

    auto fileStrategy = std::make_unique<FileOutputStrategy>(options);
    ASSERT_EQ(logger.AddOutputStrategy(std::move(fileStrategy)), ERR_OK);
    ASSERT_EQ(logger.Start(), ERR_OK);

    std::vector<std::thread> threads;
    std::atomic<int> readyCount{0};
    std::atomic<bool> start{false};
    std::atomic<size_t> successCount{0};

    const std::string message(TEST_MESSAGE_SIZE, TEST_CHAR);
    const int32_t totalMessages = TEST_THREADS * TEST_MESSAGES_COUNT;

    auto worker = [&]() {
        readyCount++;
        while (!start) {
            std::this_thread::yield();
        }
        for (int i = 0; i < TEST_MESSAGES_COUNT; ++i) {
            auto errCode = logger.Append(message.c_str(), message.size());
            if (errCode == ERR_OK) {
                successCount.fetch_add(1, std::memory_order_relaxed);
            }
            std::this_thread::sleep_for(1us);
        }
    };

    for (int i = 0; i < TEST_THREADS; i++) {
        threads.emplace_back(worker);
    }

    while (readyCount < TEST_THREADS) {
        std::this_thread::sleep_for(1ms);
    }

    PerfTimer timer;
    start = true;

    for (auto &t : threads) {
        t.join();
    }

    EXPECT_EQ(logger.ForceSync(), ERR_OK);
    double elapsed = timer.elapsed();

    GTEST_LOG_(INFO) << "[AsyncFsync PERFORMANCE REPORT]\n";
    GTEST_LOG_(INFO) << "Success: " << successCount << "\n";
    GTEST_LOG_(INFO) << "Threads: " << TEST_THREADS << "\n";
    GTEST_LOG_(INFO) << "Messages per thread: " << TEST_MESSAGES_COUNT << "\n";
    GTEST_LOG_(INFO) << "Total messages: " << totalMessages << "\n";
    GTEST_LOG_(INFO) << "Message size: " << TEST_MESSAGE_SIZE << " bytes\n";
    GTEST_LOG_(INFO) << "Elapsed time: " << elapsed << " seconds\n";
    GTEST_LOG_(INFO) << "Throughput: " << totalMessages / elapsed << " msg/sec\n";

    EXPECT_EQ(logger.Stop(), ERR_OK);
    EXPECT_GT(static_cast<double>(successCount.load()), totalMessages * 0.95); // 至少95%成功
}

/**
 * @tc.name: AsyncFsyncPerformanceTest_002
 * @tc.desc: verify AsyncFsync sync latency performance
 * @tc.type: PERF
 */
TEST_F(AsyncFsyncPerformanceTest, AsyncFsyncPerformanceTest_002)
{
    auto& asyncFsync = AsyncFsync::GetInstance();
    asyncFsync.SetSyncInterval(100); // 100ms 间隔
    
    const int testRounds = 100;
    std::vector<double> latencies;
    latencies.reserve(testRounds);
    
    for (int round = 0; round < testRounds; ++round) {
        std::string testFile = testDir_ + "/latency_" + std::to_string(round) + ".log";
        int fd = open(testFile.c_str(), O_CREAT | O_WRONLY | O_TRUNC, 0644);
        ASSERT_GE(fd, 0);
        
        asyncFsync.AddFile(fd);
        
        // 写入数据
        std::string testData = "Latency test data for round " + std::to_string(round) + "\n";
        ssize_t written = write(fd, testData.c_str(), testData.size());
        EXPECT_GT(written, 0);
        
        // 测量同步延迟
        PerfTimer timer;
        asyncFsync.RequestImmediateSync(fd);
        
        // 等待同步完成的信号（这里简化为固定等待）
        std::this_thread::sleep_for(std::chrono::microseconds(100));
        
        double latency = timer.elapsed() * 1000; // 转换为毫秒
        latencies.push_back(latency);
        
        asyncFsync.RemoveFile(fd);
        close(fd);
    }
    
    // 计算统计数据
    double sum = 0;
    double minLatency = latencies[0];
    double maxLatency = latencies[0];
    
    for (double latency : latencies) {
        sum += latency;
        if (latency < minLatency) minLatency = latency;
        if (latency > maxLatency) maxLatency = latency;
    }
    
    double avgLatency = sum / testRounds;
    
    GTEST_LOG_(INFO) << "[AsyncFsync LATENCY PERFORMANCE REPORT]\n";
    GTEST_LOG_(INFO) << "Test rounds: " << testRounds << "\n";
    GTEST_LOG_(INFO) << "Average latency: " << avgLatency << " ms\n";
    GTEST_LOG_(INFO) << "Min latency: " << minLatency << " ms\n";
    GTEST_LOG_(INFO) << "Max latency: " << maxLatency << " ms\n";
    
    // 基本性能断言
    EXPECT_LT(avgLatency, 10.0); // 平均延迟应小于10ms
    EXPECT_LT(maxLatency, 50.0); // 最大延迟应小于50ms
}

/**
 * @tc.name: AsyncFsyncPerformanceTest_003
 * @tc.desc: verify AsyncFsync throughput with different sync intervals
 * @tc.type: PERF
 */
TEST_F(AsyncFsyncPerformanceTest, AsyncFsyncPerformanceTest_003)
{
    std::vector<uint32_t> intervals = {50, 100, 500, 1000}; // 不同的同步间隔
    std::map<uint32_t, double> throughputResults;
    
    const int messagesPerTest = 5000;
    const std::string testMessage(TEST_MESSAGE_SIZE, TEST_CHAR);
    
    for (uint32_t interval : intervals) {
        auto& logger = AsyncLogger<>::GetInstance();
        
        FileOutputOptions options;
        options.filePathPattern = testDir_ + "/throughput_" + std::to_string(interval) + ".log";
        options.useAsyncFsync = true;
        options.asyncFsyncIntervalMs = interval;
        options.maxFileSize = 10 * TEST_MB;
        
        auto fileStrategy = std::make_unique<FileOutputStrategy>(options);
        logger.AddOutputStrategy(std::move(fileStrategy));
        logger.Start();
        
        PerfTimer timer;
        
        // 发送消息
        for (int i = 0; i < messagesPerTest; ++i) {
            logger.Append(testMessage.c_str(), testMessage.size());
            if (i % 1000 == 0) {
                std::this_thread::sleep_for(std::chrono::microseconds(10));
            }
        }
        
        logger.ForceSync();
        double elapsed = timer.elapsed();
        
        logger.Stop();
        
        double throughput = messagesPerTest / elapsed;
        throughputResults[interval] = throughput;
        
        GTEST_LOG_(INFO) << "Interval " << interval << "ms: " << throughput << " msg/sec\n";
        
        // 清理
        std::this_thread::sleep_for(std::chrono::milliseconds(100));
    }
    
    GTEST_LOG_(INFO) << "[AsyncFsync THROUGHPUT COMPARISON REPORT]\n";
    for (const auto& result : throughputResults) {
        GTEST_LOG_(INFO) << "Interval " << result.first << "ms: " << result.second << " msg/sec\n";
    }
    
    // 验证基本性能要求
    for (const auto& result : throughputResults) {
        EXPECT_GT(result.second, 1000.0); // 每秒至少1000条消息
    }
}

} // namespace SystemLog
} // namespace Base
